package com.lsh.ofc.worker.task;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lsh.base.common.exception.BusinessException;
import com.lsh.ofc.core.constant.Constants;
import com.lsh.ofc.core.entity.*;
import com.lsh.ofc.core.enums.*;
import com.lsh.ofc.core.model.StoSoHead;
import com.lsh.ofc.core.service.OfcCustomerService;
import com.lsh.ofc.core.service.OfcOrderService;
import com.lsh.ofc.core.service.OfcSoService;
import com.lsh.ofc.core.service.OfcStoCreateService;
import com.lsh.ofc.core.util.IdGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Project Name: lsh-ofc
 * Created by fuhao
 * Date: 18/6/19
 * Time: 18/6/19.
 * 北京链商电子商务有限公司
 * Package name:com.lsh.ofc.worker.task.
 * desc:类功能描述
 * @author fuhao
 */
@Slf4j
@Component
public class OfcStoCreateJob extends AbstractOfcTaskJob {

    @Autowired
    private OfcSoService ofcSoService;

    @Autowired
    private OfcCustomerService ofcCustomerService;

    @Autowired
    private OfcStoCreateService ofcStoCreateService;

    @Autowired
    private OfcOrderService ofcOrderService;


    @Override
    protected OfcTaskType getFetchTaskType() {
        return OfcTaskType.STO_CREATE;
    }

    @Override
    protected int processTask(OfcTask task) throws BusinessException {
        Long stoCode2orderCode = task.getRefId();
        String content = task.getContent();
        log.info("【{}】 sto include so : {}", stoCode2orderCode, content);
        List<String> sourceSoBillCodeList = JSON.parseArray(content, String.class);
        List<StoSoHead> sourceSoHeadList = new ArrayList<>();
        OfcSoHead filter;
        for (String soBillCode : sourceSoBillCodeList) {
            filter = new OfcSoHead();
            filter.setSoBillCode(soBillCode);
            OfcSoHead ofcSoHead = this.ofcSoService.findOne(filter, false);

            StoSoHead stoSoHead = new StoSoHead();
            BeanUtils.copyProperties(ofcSoHead, stoSoHead);

            sourceSoHeadList.add(stoSoHead);
        }

        StoSoHead sourceSoHeadFirst = sourceSoHeadList.get(0);

        log.info("preWarehouseCode : {}, supplierDc: {},supplierOrg: " + sourceSoHeadFirst.getSupplierOrg(), sourceSoHeadFirst.getPreWarehouseCode(), sourceSoHeadFirst.getSupplierDc());

        OfcOrderHead stoOrderHead = this.builderOrderHead(stoCode2orderCode, sourceSoHeadFirst);
        OfcSoHead stoSoHead = this.builderSoHead(stoOrderHead, sourceSoHeadFirst);

        BigDecimal totalSkuOrderQty = BigDecimal.ZERO;
        BigDecimal totalSkuSupplyQty = BigDecimal.ZERO;
        Map<Long, OfcOrderDetail> target4OrderDetailMap = new HashMap<>();
        Map<Long, OfcSoDetail> target4SoDetailMap = new HashMap<>();
        Integer itemNo = 0;
        List<String> soBillCodes = new ArrayList<>();
        for (StoSoHead sourceSoHead : sourceSoHeadList) {
            String stoBillCode = stoSoHead.getSoBillCode();
            totalSkuOrderQty = totalSkuOrderQty.add(sourceSoHead.getTotalSkuOrderQty());
            totalSkuSupplyQty = totalSkuSupplyQty.add(sourceSoHead.getTotalSkuSupplyQty());

            List<OfcSoDetail> sourceSoDetailList = ofcSoService.findDtails(sourceSoHead.getSoBillCode());
            for (OfcSoDetail sourceSoDetail : sourceSoDetailList) {
                log.info("item_no: " + itemNo);
                this.BuilderOrderDetail(stoCode2orderCode, target4OrderDetailMap, sourceSoDetail);
                this.BuilderSoDetail(stoBillCode, target4SoDetailMap, sourceSoDetail, ++itemNo);
            }

            soBillCodes.add(sourceSoHead.getSoBillCode());
        }

        stoOrderHead.getDetails().addAll(target4OrderDetailMap.values());
        stoSoHead.getDetails().addAll(target4SoDetailMap.values());

        this.fillBillCodes2Ext(stoOrderHead, soBillCodes);
        this.fillBillCodes2Ext(stoSoHead, soBillCodes);

        stoOrderHead.setTotalSkuOrderQty(totalSkuOrderQty);

        stoSoHead.setTotalSkuOrderQty(totalSkuOrderQty);
        stoSoHead.setTotalSkuSupplyQty(totalSkuSupplyQty);

        return ofcStoCreateService.create(stoOrderHead, Collections.singletonList(stoSoHead));
    }

    /**
     * 构建STO 订单头信息
     *
     * @param orderCode    订单id
     * @param sourceSoHead 普通订单头信息
     * @return OfcOrderHead
     */
    private OfcOrderHead builderOrderHead(Long orderCode, StoSoHead sourceSoHead) {
        // 按照门店纬度汇总
        OfcOrderHead targetOrderHead = new OfcOrderHead();
        targetOrderHead.setOrderCode(orderCode);
        // 来自so头信息
        targetOrderHead.setRegionCode(sourceSoHead.getRegionCode());
        //默认用前置仓ID当作 addressCode
        targetOrderHead.setAddressCode(Long.valueOf(sourceSoHead.getPreWarehouseCode()));
        targetOrderHead.setWarehouseCode(sourceSoHead.getWarehouseCode());
        targetOrderHead.setWarehouseName(sourceSoHead.getWarehouseName());
        targetOrderHead.setSecondDistributionFlag(sourceSoHead.getSecondDistributionFlag());
        targetOrderHead.setPreWarehouseCode(sourceSoHead.getPreWarehouseCode());

        Integer transTime = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
        // 组织ext
        OfcOrderHead filter = new OfcOrderHead();
        filter.setOrderCode(sourceSoHead.getOrderCode());
        OfcOrderHead ofcOrderHead = ofcOrderService.findOne(filter, false);
        JSONObject addressInfo = JSON.parseObject(ofcOrderHead.getAddressInfo());

        targetOrderHead.setAddressInfo(this.initAddressInfo(addressInfo).toJSONString());
        // 来自customer
        OfcCustomer customer = this.getCustomer(targetOrderHead);

        Map<String, String> ext = new HashMap<>();
        ext.put(Constants.ORDER_H_MP_CUST_CODE, customer.getMpCustCode());
        ext.put(Constants.ORDER_H_TRANS_TIME, transTime.toString());
        ext.put(Constants.OFC_ORDER_LOGISTICS_MODE, LogisticsTypeEnum.DC_2_PRE_WAREHOUSE.getType().toString());
        targetOrderHead.setExt(JSON.toJSONString(ext));
        // 默认设置
        targetOrderHead.setFulfillStatus(FulfillStatus.NEW.getValue());
        targetOrderHead.setOrderDistributionType(DistributionType.SEED_STO.getCode());
        targetOrderHead.setDistributionWay(sourceSoHead.getDistributionWay());
        // 调拨单默认金额为0
        targetOrderHead.setOrderAmount(BigDecimal.ZERO);
        targetOrderHead.setOrderTime(transTime);
        targetOrderHead.setDetails(new ArrayList<OfcOrderDetail>());

        return targetOrderHead;
    }

    /**
     * 构建sto so 头信息
     *
     * @param stoOrderHead sto订单头信息
     * @param sourceSoHead 普通订单so信息
     * @return OfcSoHead
     */
    private OfcSoHead builderSoHead(OfcOrderHead stoOrderHead, StoSoHead sourceSoHead) {
        OfcSoHead targetSoHead = new OfcSoHead();
        targetSoHead.setSoBillCode(IdGenerator.getId());
        // 来自so头信息
        targetSoHead.setSupplierId(sourceSoHead.getSupplierId());
        targetSoHead.setSupplierDc(sourceSoHead.getSupplierDc());
        targetSoHead.setSupplierOrg(sourceSoHead.getSupplierOrg());
        targetSoHead.setFulfillWms(sourceSoHead.getFulfillWms());
        targetSoHead.setFulfillChannel(sourceSoHead.getFulfillChannel());

        // 来自汇总so信息
        targetSoHead.setOrderCode(stoOrderHead.getOrderCode());
        targetSoHead.setOrderTime(stoOrderHead.getOrderTime());
        targetSoHead.setRegionCode(stoOrderHead.getRegionCode());
        targetSoHead.setAddressCode(stoOrderHead.getAddressCode());
        targetSoHead.setWarehouseCode(stoOrderHead.getWarehouseCode());
        targetSoHead.setWarehouseName(stoOrderHead.getWarehouseName());
        targetSoHead.setSecondDistributionFlag(stoOrderHead.getSecondDistributionFlag());
        targetSoHead.setDistributionWay(stoOrderHead.getDistributionWay());
        targetSoHead.setOrderDistributionType(stoOrderHead.getOrderDistributionType());
        targetSoHead.setPreWarehouseCode(stoOrderHead.getPreWarehouseCode());
        // 组织ext 信息
        JSONObject ext_so = JSON.parseObject(stoOrderHead.getExt());
        ext_so.put(Constants.SO_H_SUPPLIER_CODE, stoOrderHead.getPreWarehouseCode());
        Integer transTime = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
        ext_so.put(Constants.SO_H_TRANS_TIME, transTime.toString());
        targetSoHead.setExt(JSON.toJSONString(ext_so));

        // 默认值
        targetSoHead.setSoStatus(SoStatus.UNCREATED.getValue());
        targetSoHead.setDetails(new ArrayList<OfcSoDetail>());

        return targetSoHead;
    }


    /**
     * 完善sto 订单ext信息, 后期pms 需要
     *
     * @param targetOrderHead 构建订单头信息
     * @param soBillCodes     合单需要的so主键
     */
    private void fillBillCodes2Ext(OfcOrderHead targetOrderHead, List<String> soBillCodes) {

        JSONObject headExt = JSON.parseObject(targetOrderHead.getExt());
        headExt.put("sto_ref_sobillcode", soBillCodes);
        targetOrderHead.setExt(JSON.toJSONString(headExt));
    }

    /**
     * 完善sto so ext信息, 后期pms 需要
     *
     * @param targetSoHead 构建so单头信息
     * @param soBillCodes  合单需要的so主键
     */
    private void fillBillCodes2Ext(OfcSoHead targetSoHead, List<String> soBillCodes) {

        JSONObject soHeadExt = JSON.parseObject(targetSoHead.getExt());
        soHeadExt.put("sto_ref_sobillcode", soBillCodes);
        targetSoHead.setExt(JSON.toJSONString(soHeadExt));
    }

    /**
     * @param soBillCode         合单的so主键
     * @param target4SoDetailMap 合单详情map
     * @param sourceSoDetail     合单so详情
     * @param itemNo             行项目
     */
    private void BuilderSoDetail(String soBillCode, Map<Long, OfcSoDetail> target4SoDetailMap, OfcSoDetail sourceSoDetail, Integer itemNo) {

        if (target4SoDetailMap.containsKey(sourceSoDetail.getGoodsCode())) {

            OfcSoDetail soDetailTarget = target4SoDetailMap.get(sourceSoDetail.getGoodsCode());

            soDetailTarget.setGoodsAmount(soDetailTarget.getGoodsAmount().add(sourceSoDetail.getGoodsAmount()));
            soDetailTarget.setSkuOrderQty(soDetailTarget.getSkuOrderQty().add(sourceSoDetail.getSkuOrderQty()));
            soDetailTarget.setSkuSupplyQty(soDetailTarget.getSkuSupplyQty().add(sourceSoDetail.getSkuSupplyQty()));
        } else {
            OfcSoDetail soDetailTarget = new OfcSoDetail();
            soDetailTarget.setSoBillCode(soBillCode);
            soDetailTarget.setItemNo(itemNo * 10);
            soDetailTarget.setGoodsCode(sourceSoDetail.getGoodsCode());
            soDetailTarget.setGoodsName(sourceSoDetail.getGoodsName());
            soDetailTarget.setGoodsSaleUnit(sourceSoDetail.getGoodsSaleUnit());
            soDetailTarget.setGoodsPrice(sourceSoDetail.getGoodsPrice());
            soDetailTarget.setGoodsAmount(sourceSoDetail.getGoodsAmount());
            soDetailTarget.setSkuCode(sourceSoDetail.getSkuCode());
            soDetailTarget.setSkuSupplyCode(sourceSoDetail.getSkuSupplyCode());
            soDetailTarget.setSkuSupplyPrice(sourceSoDetail.getSkuSupplyPrice());
            soDetailTarget.setSkuOrderQty(sourceSoDetail.getSkuOrderQty());
            soDetailTarget.setSkuSupplyQty(sourceSoDetail.getSkuSupplyQty());
            soDetailTarget.setTaxRate(sourceSoDetail.getTaxRate());
            soDetailTarget.setExt(sourceSoDetail.getExt());

            target4SoDetailMap.put(sourceSoDetail.getGoodsCode(), soDetailTarget);
        }
    }

    /**
     * @param orderCode             合单订单主键
     * @param target4OrderDetailMap 合单订单详情map
     * @param sourceSoDetail        合单so详情
     */
    private void BuilderOrderDetail(Long orderCode, Map<Long, OfcOrderDetail> target4OrderDetailMap, OfcSoDetail sourceSoDetail) {
        if (target4OrderDetailMap.containsKey(sourceSoDetail.getGoodsCode())) {
            OfcOrderDetail orderDetailTarget = target4OrderDetailMap.get(sourceSoDetail.getGoodsCode());
            BigDecimal goodsQty = sourceSoDetail.getSkuOrderQty().divide(sourceSoDetail.getGoodsSaleUnit(), 4, BigDecimal.ROUND_HALF_UP);
            BigDecimal totalGoodsQty = orderDetailTarget.getGoodsQty().add(goodsQty);
            orderDetailTarget.setGoodsQty(totalGoodsQty);

            BigDecimal totalGoodsAmount = orderDetailTarget.getGoodsAmount().add(sourceSoDetail.getGoodsAmount());
            orderDetailTarget.setGoodsAmount(totalGoodsAmount);

            BigDecimal totalSkuQty = orderDetailTarget.getSkuQty().add(sourceSoDetail.getSkuOrderQty());
            orderDetailTarget.setSkuQty(totalSkuQty);
        } else {
            OfcOrderDetail orderDetailTarget = new OfcOrderDetail();
            orderDetailTarget.setOrderCode(orderCode);
            orderDetailTarget.setGoodsCode(sourceSoDetail.getGoodsCode());
            orderDetailTarget.setGoodsName(sourceSoDetail.getGoodsName());
            orderDetailTarget.setGoodsSaleUnit(sourceSoDetail.getGoodsSaleUnit());
            orderDetailTarget.setGoodsPrice(sourceSoDetail.getGoodsPrice());
            BigDecimal goodsQty = sourceSoDetail.getSkuOrderQty().divide(sourceSoDetail.getGoodsSaleUnit(), 4, BigDecimal.ROUND_HALF_UP);
            orderDetailTarget.setGoodsQty(goodsQty);
            orderDetailTarget.setGoodsAmount(sourceSoDetail.getGoodsAmount());
            orderDetailTarget.setSkuCode(sourceSoDetail.getSkuCode());
            orderDetailTarget.setSkuQty(sourceSoDetail.getSkuOrderQty());
            // 2019-02-28 下发sto
            orderDetailTarget.setExt(sourceSoDetail.getExt());
            target4OrderDetailMap.put(sourceSoDetail.getGoodsCode(), orderDetailTarget);
        }
    }


    private JSONObject initAddressInfo(JSONObject addressInfoJson) {
        JSONObject addressInfo = new JSONObject();
        //超市名称
        addressInfo.put("market_name", addressInfoJson.getString("pre_warehouse_name"));
        addressInfo.put("province_name", "北京");
        addressInfo.put("city_name", "北京");
        addressInfo.put("county_name", "北京");
        addressInfo.put("address", "北京餐馆前置仓");
        //联系人
        addressInfo.put("contact_name", "北京餐馆前置仓");
        //联系人电话
        addressInfo.put("contact_phone", "00000000000");
        addressInfo.put("real_position", "0");
        //大车限行
        addressInfo.put("trans_limit", "0");
        // TODO
        addressInfo.put(Constants.ORDER_PRE_WAREHOUSE_CODE,addressInfoJson.getString(Constants.ORDER_PRE_WAREHOUSE_CODE));
        addressInfo.put(Constants.ORDER_PRE_WAREHOUSE_NAME,addressInfoJson.getString(Constants.ORDER_PRE_WAREHOUSE_NAME));
        addressInfo.put(Constants.ORDER_DELIVERY_WAY,addressInfoJson.getString(Constants.ORDER_DELIVERY_WAY));
        addressInfo.put(Constants.ORDER_IS_IN_DMALL,addressInfoJson.getString(Constants.ORDER_IS_IN_DMALL));

        return addressInfo;
    }

    /**
     *
     * @param ofcOrderHead
     * @return
     * @throws BusinessException
     */
    private OfcCustomer getCustomer(OfcOrderHead ofcOrderHead) throws BusinessException {
        //校验并更新用户信息
        OfcCustomer param = new OfcCustomer();
        JSONObject addressInfo = JSON.parseObject(ofcOrderHead.getAddressInfo());

        param.setRegionCode(ofcOrderHead.getRegionCode());
        param.setCustCode(ofcOrderHead.getAddressCode());
        param.setCustName(addressInfo.getString("market_name"));
        param.setProvince(addressInfo.getString("province_name"));
        param.setCity(addressInfo.getString("city_name"));
        param.setDistrict(addressInfo.getString("county_name"));
        param.setAddress(addressInfo.getString("address"));
        param.setContactName(addressInfo.getString("contact_name"));
        param.setContactPhone(addressInfo.getString("contact_phone"));
        param.setLocation(addressInfo.getString("real_position"));
        Integer transLimit = addressInfo.getInteger("trans_limit");
        param.setExt(JSON.toJSONString(Collections.singletonMap(Constants.USER_ADDRESS_TRANS_LIMIT, transLimit)));
        // sto调拨默认是链商自建客户号类型
        param.setCusType(CusType.LSH_NEW.getValue());

        return this.ofcCustomerService.updateCustomer(param);
    }


    @Override
    protected boolean filterFlag(OfcTask task) {
        return false;
    }

    @Override
    protected List<OfcTask> fetchTasks(OfcTaskType type, Set<OfcTaskStatus> statuses, int shardingCount, List<Integer> shardingItems, int fetchSize) {
        return super.defaultFetchTasks(type, statuses, shardingCount, shardingItems, fetchSize);
    }
}
